/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.performance;

import cgl.narada.util.ByteUtilities;
import cgl.narada.util.StatUtils;
/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: </p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */

public class ComputeMetrics {
  private long []delays=new long[100];
  private long lastDelay=0, _delay=0;
  private int tracker=0;
  private int numVals=100;
  private static int numberOfLosses=0;
  private int savedTracker=0;
  private double jitter=0;
  private int c=0;
  private long[] newArray;
  public ComputeMetrics() {

  }


  public LinkPerformanceDataImpl[] calculateMetrics(LinkPerformanceDataImpl[] pmetrics,
                                          byte[] perfData, int lossTrack){
    long stopTime = System.currentTimeMillis();
    byte[] losstrackbytevalue = new byte[4];
    System.arraycopy(perfData, 10, losstrackbytevalue, 0, 4);
    int returnedLossTracker = ByteUtilities.getInt(losstrackbytevalue);

    byte[] delayArray = new byte[8];
    System.arraycopy(perfData, 2, delayArray, 0, 8);
    long startTime = ByteUtilities.getLong(delayArray);
    lastDelay = _delay;
    _delay = (stopTime - startTime) / 2;
    delays[tracker % 100] = _delay;
    numVals = 100;
    if (tracker < 99) {
      numVals = tracker;
    }
    tracker++;
    c++;
    for (int i=0;i<pmetrics.length;i++){
      if (pmetrics[i].getParameterValue().equalsIgnoreCase("NM")){
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("Mean")){
        pmetrics[i].setParameterValue(java.lang.Double.toString(StatUtils.computeMean(delays, numVals, 0)));
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("Std Dev")){
        if (c==10){
          c=0;
          pmetrics[i].setParameterValue(java.lang.Double.toString
                                        (StatUtils.computeStandardDeviationWithoutOutliers(delays, numVals)));
          newArray=StatUtils.getValuesWithoutOutliers(delays, numVals);
          for (int k = 0; k < newArray.length; k++) {
            delays[k]=newArray[k];
          }
          tracker=newArray.length-1;
        }else
        pmetrics[i].setParameterValue(java.lang.Double.toString
                                      (StatUtils.computeStandardDeviation(delays, numVals, 0)));
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("jitter")){
        jitter=StatUtils.computeJitter(jitter, lastDelay, _delay);
        pmetrics[i].setParameterValue(java.lang.Double.toString(jitter));
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("throughput")&&c==10){
        c=0;
        pmetrics[i].setParameterValue(java.lang.Double.toString
                                      (StatUtils.computeStandardDeviationWithoutOutliers(delays, numVals)));
        newArray=StatUtils.getValuesWithoutOutliers(delays, numVals);
        for (int k = 0; k < newArray.length; k++) {
          delays[k]=newArray[k];
        }
        tracker=newArray.length-1;
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("loss rate")){
        pmetrics[i].setParameterValue(
            java.lang.Double.toString(computeLossRate(tracker, lossTrack, returnedLossTracker))
            );
      }
    }//end for
    return pmetrics;
  }

  public LinkPerformanceDataImpl[] calculateMetrics(LinkPerformanceDataImpl[] pmetrics,
                                          byte[] perfData ){
    long stopTime = System.currentTimeMillis();
    byte[] delayArray = new byte[8];
    System.arraycopy(perfData, 2, delayArray, 0, 8);
    long startTime = ByteUtilities.getLong(delayArray);
    lastDelay = _delay;
    _delay = (stopTime - startTime) / 2;
    delays[tracker % 100] = _delay;
    numVals = 100;
    if (tracker < 100) {
      numVals = tracker;
    }
    tracker++;
    c++;
    for (int i=0;i<pmetrics.length;i++){
      if (pmetrics[i].getParameterValue().equalsIgnoreCase("NM")){
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("Mean")){
        pmetrics[i].setParameterValue(java.lang.Double.toString(StatUtils.computeMean(delays, numVals, 0)));
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("Std Dev")){
        if (c==10){
          c=0;
          pmetrics[i].setParameterValue(java.lang.Double.toString
                                        (StatUtils.computeStandardDeviationWithoutOutliers(delays, numVals)));
          newArray=StatUtils.getValuesWithoutOutliers(delays, numVals);
          for (int k = 0; k < newArray.length; k++) {
            delays[k]=newArray[k];
          }
          tracker=newArray.length-1;
        }else
        pmetrics[i].setParameterValue(java.lang.Double.toString
                                      (StatUtils.computeStandardDeviation(delays, numVals, 0)));
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("jitter")){
        jitter=StatUtils.computeJitter(jitter, lastDelay, _delay);
        pmetrics[i].setParameterValue(java.lang.Double.toString(jitter));
      }else if (pmetrics[i].getParameterName().equalsIgnoreCase("throughput")&&c==10){
        c=0;
        pmetrics[i].setParameterValue(java.lang.Double.toString
                                      (StatUtils.computeStandardDeviationWithoutOutliers(delays, numVals)));
        newArray=StatUtils.getValuesWithoutOutliers(delays, numVals);
        for (int k = 0; k < newArray.length; k++) {
          delays[k]=newArray[k];
        }
        tracker=newArray.length-1;
      }
    }//end for
    return pmetrics;
  }


  public double computeLossRate(int numberOfMessages, int lossTracker, int returnedLossTracker) {
    double lossRate=0;
    if (lossTracker!=returnedLossTracker) numberOfLosses++;
    lossRate=(numberOfLosses*100)/numberOfMessages;
    return lossRate;
  }

  public long[] getLatencyValues(){
    int t;
    if (tracker>100) t=100;
      else
        t=tracker;
    long [] newValues=new long[t];
    for (int i = 0; i < t; i++) {
      newValues[i]=delays[i];
    }
    return newValues;

  }
}

